﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NMbsDuplex.TCPServerX.Deamon
{
    using System.IO;
    using System.Net.Sockets;

    #region 小于等于32kb的文件 直接使用Socket工具函数SendFile()完成
    public enum BFileTransMethod
    {
        SendByRawSocket, SendOnce, SendByTask, Big5,
    }
    #endregion

    public static class TCPExtension
    {
        // Socket扩展 发送文本
        public static int SendBytes(this Socket refSock,
            string CombinMsg, Encoding EnCoder)
        {
            byte[] buffer = EnCoder.GetBytes(CombinMsg);
            int N = refSock.Send(buffer, 0, buffer.Length, SocketFlags.None);
            return N;
        }

        /* Socket扩展 接受文本 解析编码为运行时传入 */
        public static string RecvBytes(this Socket refSock,
            Encoding EnCoder, ref int N)
        {
            /* Tips : 有进有出用ref 只出不进用out */
            byte[] buffer = new byte[TCPBase.BUFSIZ];
            N = refSock.Receive(buffer);
            string receivingMsg = EnCoder.GetString(buffer, 0, N);
            return receivingMsg;
        }

        #region TCP分片儿传输
        public static long _TransFile(this Socket refSock,
            string fileUrl, BFileTransMethod mode)
        {
            /* 
             * 1.文件名长度 [255][255][255][255] 2.文件名bytes[255] 
             * 3.CRC32循环校检值 - 一边传输一边计算 [128][1][0][0]
             * 4.文件名转码字节流byte[M] + 整个文件流bytes[N] = 第4个区块
             */
            var memoryCache = new List<byte>(ushort.MaxValue);
            using (var sr = new FileStream(fileUrl, FileMode.Open))
            {
                Encoding coder = Encoding.UTF8;
                string realName = Path.GetFileName(sr.Name);
                byte[] block4 = coder.GetBytes(realName);
                // 1.压入文件名到首部块1
                memoryCache.Add(Convert.ToByte(block4.Length));
                // 2.压入首部[1-4]比特位值 并生成CRC32值写入首部[5-9]
                byte[] h4 = BitConverter.GetBytes(sr.Length);
                for (int i = 0; i < 4; i++)
                {
                    memoryCache.Add(h4[i]);
                }
                // 3.模拟生成假的CRC32循环校检值
                memoryCache.Add(Convert.ToByte('C'));
                memoryCache.Add(Convert.ToByte('R'));
                memoryCache.Add(Convert.ToByte('C'));
                memoryCache.Add(Convert.ToByte("32"));
                // 4.对拷文件名转码
                for (int i = 0; i < block4.Length; i++)
                {
                    memoryCache.Add(block4[i]);
                }
                // 5.对拷文件内容bytes流
                for (int position = 0; position < sr.Length; position++)
                {
                    // 逐字逐句地读取每一个字节到内存数据结构 追加到尾部
                    int code = sr.ReadByte();
                    byte b = Convert.ToByte(code);
                    memoryCache.Add(b);
                }
                // 6.传输开始之前 先清洗内存并检查一次CRC32值
                memoryCache.TrimExcess();
            }
            /* 7.TCP分片传输 单词传输值不能超过8192[8Kb] */
            const int TIFSIZ = short.MaxValue / 4;
            int page, rest;
            rest = memoryCache.Count % TIFSIZ;
            page = memoryCache.Count / TIFSIZ + ((rest == 0) ? 0 : 1);
            var transInfo = string.Format("本次传输一共进行{0}次,分片大小{1:F}kb,尾片长度{2:F}kb", page, (float)(TIFSIZ / 1024), (float)(rest / 1024));
            Console.WriteLine(transInfo);
            int N = refSock.Send(memoryCache.ToArray());
            Console.WriteLine("refSock已发送字节数{0}bytes", N);
            return -1;
        }
        #endregion
    }
}
